package com.objecteffects.template.web.action;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.inject.Inject;

import com.objecteffects.template.model.TumblrBlogEntity;
import com.objecteffects.template.model.UserEntity;
import com.objecteffects.template.oauth.Tumblr;
import com.objecteffects.template.service.UserEntityService;
import com.objecteffects.template.util.logger.InjectLogger;
import com.objecteffects.template.web.utils.LoginRequired;
import com.objecteffects.template.web.utils.TumblrAccessToken;

import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.TumblrApi;
import org.scribe.model.Token;
import org.scribe.oauth.OAuthService;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.routines.UrlValidator;

import org.slf4j.Logger;

import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.SimpleMessage;
import net.sourceforge.stripes.validation.Validate;

/**
 * @author Rusty Wright
 */
@LoginRequired
public class TumblrStartUrlActionBean extends BaseActionBean {
    @InjectLogger
    private Logger log;

    @Validate(required = true, on = {
        "proceed"
    })
    private String tumblrUrl;

    private final List<String> tumblrUrls = new ArrayList<>();

    private final PostType postType = PostType.POSTS;

    private final UserEntityService userEntityService;
    private final TumblrAccessToken tumblrAccessToken;

    @Inject
    TumblrStartUrlActionBean(final UserEntityService _userEntityService,
        final TumblrAccessToken _tumblrAccessToken) {
        this.userEntityService = _userEntityService;
        this.tumblrAccessToken = _tumblrAccessToken;
    }

    @DefaultHandler
    public Resolution startHandler() {
        final UserEntity userEntity =
            this.userEntityService.findById(this.getContext().getUserId());

        this.log.debug("userEntity: {}", userEntity);

        for (final TumblrBlogEntity each : userEntity.getTumblrBlogEntities()) {
            this.tumblrUrls.addAll(each.getUrls());
        }

        Collections.sort(this.tumblrUrls);

        return new ForwardResolution(TemplateView.TUMBLR_START_URL);
    }

    public Resolution proceed() {
        if (!this.trimAndValidateUrl()) {
            this.log.error("invalid url: {}", this.tumblrUrl);

            this.getContext().getMessages()
            .add(new SimpleMessage("Invalid url."));

            return new ForwardResolution(TemplateView.ERROR);
        }

        this.getContext().setTumblrUrl(this.tumblrUrl);

        if (this.hasAccessToken()) {
            final RedirectResolution res =
                new RedirectResolution(TumblrResponseUrlActionBean.class);

            return res;
        }

        final String authUrl = this.authUrl();

        /*
         * Step 3
         * 
         * This goes to tumblr for authentication, that redirects to
         * TumblrCallbackActionBean, that redirects to
         * TumblrResponseAllActionBean, and that redirects to the
         * action bean that calls the tumblr METHOD.
         */

        return new RedirectResolution(authUrl, false);
    }

    /**
     * Normalize the url, so to speak, by removing the leading scheme,
     * if any and removing tumblr.com, if any. Then temporarily add
     * them and use Commons Validator to check it.
     */
    private boolean trimAndValidateUrl() {
        this.tumblrUrl =
            StringUtils.removeStartIgnoreCase(this.tumblrUrl, "http://");

        this.tumblrUrl =
            StringUtils.removeStartIgnoreCase(this.tumblrUrl, "https://");

        this.tumblrUrl =
            StringUtils.removeEndIgnoreCase(this.tumblrUrl, ".tumblr.com");

        final UrlValidator urlValidator = new UrlValidator();

        if (!urlValidator.isValid("http://" + this.tumblrUrl + ".tumblr.com")) {
            this.log.warn("invalid url: {}", this.tumblrUrl);
            return false;
        }

        return true;
    }

    /**
     * @return
     */
    private String authUrl() {
        final String callbackUrl =
            "http://" + this.getContext().getRequest().getServerName() + ":" +
                this.getContext().getRequest().getServerPort() +
                Tumblr.CALLBACK_PATH;

        this.log.debug("callbackUrl: {}", callbackUrl);

        // Step 1
        final OAuthService service =
            new ServiceBuilder().provider(TumblrApi.class)
            .apiKey(Tumblr.CONSUMER_KEY).apiSecret(Tumblr.CONSUMER_SECRET)
            .callback(callbackUrl).build();

        /*
         * temporary credentials; scribe Token includes token and
         * secret
         */
        final Token requestToken = service.getRequestToken();

        this.log.debug("requestToken: {}", requestToken.getToken());

        this.getContext().setRequestToken(requestToken);

        // Step 3
        final String authUrl = service.getAuthorizationUrl(requestToken);

        this.log.debug(String.format("authUrl: %s", authUrl));

        return authUrl;
    }

    private boolean hasAccessToken() {
        final Token accessToken =
            this.tumblrAccessToken.fetchToken(this.tumblrUrl, this.getContext()
                .getUserId());

        if (accessToken == null) {
            return false;
        }

        this.log.debug("found access token in userEntity");

        return true;
    }

    public void setTumblrUrl(final String _tumblrUrl) {
        this.tumblrUrl = _tumblrUrl;
    }

    public String getTumblrUrl() {
        return this.tumblrUrl;
    }

    public List<String> getTumblrUrls() {
        return this.tumblrUrls;
    }

    public PostType getPostType() {
        return this.postType;
    }
}
